Hey there.
Welcome back.
In this lecture we're going to be scripting the last tool for our project which is our grenade.
The purpose of this tool is to give our players the ability to do splash damage to zombies when they
feel overwhelmed with a large crowd of zombies.
So when we activate this tool, it's going to fire to the server the position of our mouse, and it's
going to throw our grenade, and then it's going to blow up and deal a whole bunch of splash damage
to the zombies.
And of course, we can hold more than one grenade.
Right now I'm holding nine and I can spam click all of these grenades and throw them out, and it's
just going to blow up all of these guys.
So let's get started.
Inside of server storage and inside of tools, we have our grenade tool right here.
And it's just one mesh part inside of there.
Let me go ahead and parent it to the workspace.
This is our grenade model.
And the plan is we're going to have the player activate this tool.
And when they activate it we're going to fire to the server the position of our mouse.
That way the server can calculate the direction to throw the grenade.
We're going to throw it and then it's going to blow up and deal any splash damage to any zombies that
are nearby.
The explosion.
So what we can go ahead and do is create a new module script inside of here to store all of the different
properties for the grenade.
I'll just call it self and we'll go ahead and return it at the end of our module.
And inside of here we want to define some things such as the base damage for the grenade, which I'll
set to a value of 250 health points.
We can also set a value of how long we want to wait before the grenade explodes.
So this can be like the fuse time.
We'll call it time until explosion.
So when the player throws the grenade, how long do we want to wait until it blows up.
And we could do a value of like three seconds.
And then another property we want to go ahead and define is how long we should wait before we delete
the grenade off of the map and clean it up.
So we could call this lifetime after explosion.
And I'll just set it to something like five seconds.
And now I want to go ahead and define a table of the different damage ranges based on how close the
zombie is to the explosion.
So for example, if the zombie is within three studs of the epicenter of the explosion, that I want
to apply a multiplier to the base damage to boost that base damage up.
However, if the zombie is farther away from the grenade, let's say the zombies 20 studs away, then
I want to apply a lower multiplier for the damage.
So let's go ahead and define a table called Damage Ranges.
And inside of here, we'll just have a whole bunch of different tables for the different damage ranges.
We'll have a minimum and a maximum value for the range.
So the minimum value for this first one will be zero.
So between zero and then the max we'll do something like three studs.
And I want this value to be inclusive.
And I want this value to be exclusive.
What do I mean by that.
Well I want this to include any zombies who are within 0 to 3 studs in the explosion range.
But I don't want to include the value of three.
I want the distance to be any value below three, and then we could state what the multiplier is going
to be.
For example, if they're within three studs, we'll set the multiplier to something like three.
And then what we can go ahead and do is copy this.
And now the minimum for this one is going to be three.
So anywhere between three.
And we could do something like five studs.
So if they're between 3 and 5 studs three is inclusive.
And we're excluding five because five is going to be the next damage range.
And we could do a multiplier of like two again.
We'll copy this.
And here we could do a range of, let's say between 5 and 7 studs.
And here we'll do a multiplier of 1.5.
We'll copy this.
We'll do another range.
This one's going to be from seven to let's say nine studs.
We'll do a damage multiplier of one.
We'll copy this.
And then between, let's say, nine studs all the way up to 13 studs will have a multiplier of 0.9.
If we're between 13 studs and let's say 17, then we'll have a multiplier of 0.7.
And then if we have a range between let's say 17 up to 25.
So I want the range for my explosion to be up to 25 studs away.
Then we'll have the multiplier be 0.5.
The next thing I want to go ahead and define is all of the properties for the explosion for our grenade.
So we're going to be using an explosion instance to detect what parts we hit or if we hit any zombies
in the map.
And that means we want to go ahead and modify some of these properties in the explosion, such as the
explosion or blast pressure, the radius of the explosion, the different types of the explosion and
stuff like that.
So let's go ahead and define some explosion properties.
For example, we'll set the blast pressure to something like 30,000.
I don't want it to be the default of 500,000, because that means when it explodes, it's going to shoot
the limbs of the zombies super far away, which I don't want.
The next property is the blast radius, and I want it to be up to 25 studs away.
There's a property called destroy joint radius percent.
And that means.
The percentage or the distance inside of here.
Do we want to destroy joints of characters that hit this explosion or the explosion?
Hit that character.
I don't want to destroy the joints of any zombies that get hit by this explosion, so I'm just going
to set the value equal to zero.
We're going to set the explosion type equal to the enemy explosion type of no craters.
So this is specifically if you have terrain in your game.
If the explosion type was set to craters.
And that means it would create divots in the terrain.
But I'm going to set it to no craters.
And then there's a property called visible.
And I want to set that equal to false, because we're going to be using our own custom particles.
Setting visible to false means it disables the default particles for the explosion.
And that way we can replace it with our own custom particles.
And that's because inside of the grenade, inside of the handle, we have the sound of the explosion,
which I'll play here.
And then we have two particle emitters, one for the explosion and one for the smoke.
So I'm going to go ahead and select both of those.
And I have a plugin which allows me to emit, let's say 100 particles out of the particle emitters.
If you would like to use this plugin I'll have it attached to the lecture.
But if I go ahead and hit emit.
That's going to be the explosion we're using for our grenade.
So we can go ahead and define how many particles we would like to spit out of those particle emitters.
So for the explosion particle amount we could do 100.
And then for the smoke particle amount we'll also do a value of 100.
Okay, now that we have that done, what we can go ahead and do is create a new local script inside
of our grenade.
We'll be using that same template as before, and I'm only going to need a section to listen to some
event handlers.
I'm not going to need any functions, and what I'm going to do is I'm going to grab the player service
to get the local player.
So we'll do player is equal to players dot local player.
And that's because I want to get the mouse object of my player.
So mouse is equal to player get mouse.
And then we can go ahead and make a reference to our tool, which is script dot parent.
And then we also want to create a remote event inside of our tool to communicate between the local script
and the server script we're going to have in this grenade.
So let's go ahead and create a new remote event in here.
And I'm going to call this my grenade event.
And then we can go ahead and refer to this grenade event.
So that's going to be tool dot grenade event.
And I want to listen for when my tool is activated.
And when it is we're going to use this grenade event and fire to the server.
And I want to give the server the position of my mouse in the workspace.
So we're going to pass mouse dot hit dot position.
And that way the server can use this position to calculate what direction the grenade should be thrown
based on the position of my character model.
So now we can go ahead and create a server script inside of our grenade.
We use the same common template.
I'll delete this section, get rid of that section.
And then we want to go ahead and get the player service.
And I'm also going to be using the debris service once again.
And then we can go ahead and make a reference to our tool script dot parent.
We'll go ahead and get the properties for the tool.
So we'll require tool dot properties.
And then I also want to get the grenade event as well.
That's equal to tool dot grenade event.
Now, since I want to give my player the ability to hold more than one grenade inside of this tool.
We have a couple attributes on this grenade called grenades left and Max grenades, which tells us up
to how many grenades can we store in this tool and how many grenades do we currently have left?
That way, when the player goes to our shop and wants to purchase a grenade, if they don't have this
grenade tool in their inventory, then we're just going to give them this new grenade tool.
And if they do have this grenade tool in their inventory, then we'll just increment this grenades left
attribute on the grenade tool.
And we'll be doing that in a little bit.
But for right now, what we want to go ahead and do is we want to listen to that grenade event when
it's fired.
So on server event we're going to connect a function, get the player, and then we'll get the mouse
position the player provides to us.
Now of course we want to make sure that the player that fired this event is actually the player that
has this tool equipped, which is why we're using the player service.
So we're going to check if this player, if it's not equal to.
And we're going to use the get player from character function and pass the parent of this tool, which
should be the player's character.
If these are two different players, then we're going to return because that means an exploiter tried
to fire this event for another player.
Another thing we want to make sure of is that the attribute of grenades left is greater than one.
So if our tool get attribute grenades left, if that is equal to zero, then we're going to return.
Otherwise we can go ahead and throw the grenade.
And that first means we want to decrease how many grenades are left in the tool.
So we'll do tool set attribute grenades left equal to tool get attribute grenades left subtracted by
one.
And then we'll go ahead and get the character which is tool dot parent.
We'll go ahead and get the player which is equal to players.
Get player from character and we'll pass the character.
And now what I want to do is I want to create a clone of the handle of my grenade, and then I'm going
to basically position the clone of this handle at my player's character and then throw it in a particular
direction.
So let's go ahead and make a clone of that.
So we'll call it actually grenade clone.
And that's going to be equal to my tool dot handle clone.
And we're going to make sure that the grenade clone is opaque.
So we're going to set transparency equal to zero.
And that's because the plan is that once the player runs out of grenades, let's say their grenade attribute
gets set to zero.
Then we want to make the handle invisible.
But we're going to make sure that when we're actually throwing a grenade that it isn't invisible.
And they're also going to set can collide on the handle equal to true because it's not enabled by default.
And then we're going to set the parent of this grenade clone equal to the workspace.
We're going to position this grenade clone.
It's going to be equal to our character's humanoid root part.
Position.
And then I want to position it a little bit in front of our players character, so we can add an additional
vector to this.
We're going to get our character's humanoid root part, dot keyframe, dot look vector and multiply
that by two.
So the position we're setting the grenade to is going to be two studs in front of our humanoid root
part.
And then we want to go ahead and calculate the direction we need to throw this grenade.
And that's going to be equal to the mouse position passed to us from the client.
And we're going to subtract that by the position of our humanoid root part.
And then we're going to get a unit normalized copy of that vector.
And then to be able to throw this grenade clone, we can go ahead and set the assembly linear velocity
to be equal to this direction.
We want to throw the grenade.
Of course, since the length of this direction is only one stud, that means this force is going to
be incredibly weak.
So we're going to bump up the force of this by multiplying the direction by 30.
So that way we actually have a little bit of force in our throw.
And then we also want to multiply or add a new vector three to this to have a curve to our throw.
So we can kind of throw it up and then it goes down.
So let's go ahead and apply a force in the y direction as well.
We could do a value of like 55 in the y direction.
And now we're going to be applying a force in the direction the player wants to throw it towards that
direction with a bit of a force upwards.
So it's like you know, we're actually throwing it.
And then once we do that, we want to go ahead and yield for our properties.
Dot time until explosion.
And then here is where we should create a new explosion instance.
Blow up the grenade and detect if we hit anything.
So we want to create a new explosion, but we also want to apply all of the properties for that explosion
from our module script.
So let's go ahead and create a new function.
I'm going to call this function Create Explosion.
And we'll pass all of the explosion properties to this function.
And we'll go ahead and get a new explosion equal to instance dot new explosion.
And for every property and value in explosion properties we'll apply that to our explosion.
And then we can go ahead and return the explosion back.
And we don't want to parent the explosion to the workspace yet, because once we parent the explosion
to the workspace, that's when it's going to blow up.
So we'll get that explosion from our create explosion function and pass properties, not explosion properties.
And before we parent the explosion to the workspace, we want to go ahead and listen to the hit event.
And it says fires.
When the explosion hits a bass part within its explosion blast radius.
So we'll connect a function to this, and we're going to get past the part that we hit and then the
distance from the epicenter of the explosion.
So we'll call this our hit part.
And then we'll get the distance.
And the issue here now is that since there are so many different limbs inside of a zombie, we only
want to make sure that we hurt a zombie once.
Because if we listen and hit or apply damage for every single limb that's in the zombie, then this
grenade is going to be way too overpowered.
So what we can go ahead and do is verify that this hit part is actually a humanoid root part.
And since there's only one humanoid root part per zombie, then we're guaranteed to only hurt them once.
So if this hip part's name is not equal to humanoid root part, then we're just going to return.
Otherwise, what we can go ahead and do is get the humanoid.
So that's going to be equal to hip part dot parent find first child which is a humanoid.
If for some reason there is no humanoid, then we're just going to return.
Otherwise, we need to check if this humanoid belongs to a player.
Because if it belongs to a player, we don't want to hurt them.
So if players get player from character, we pass hit part dot parent and we get a player from that,
then we're going to return as well.
Otherwise, what we can go ahead and do is we want to create a function for getting the damage we should
apply based on the distance away from the epicenter of the explosion.
So what we can go ahead and do is create a function and we'll call it get damage, and we'll get past
the distance away from the epicenter of the explosion.
And then we can go ahead and loop through every single range that is inside of our properties, dot
damage ranges.
And what we want to do is we want to check if this number or this distance is in between those two ranges,
the minimum and the maximum.
However, because I want the minimum value to be inclusive, but I don't want to include the max value
because the max value should be for the next range, then what I'm going to do is I'm going to create
a function called number in range.
We'll get past a number and then a minimum and a maximum value.
And since I want the maximum value to be not included in this calculation, what we can go ahead and
do is we can return.
If our number is greater than or equal to the minimum number, and our number is less than the max number,
not less than or equal to, but less than the max number, then we're going to return true.
Otherwise we'll return false.
So we're inclusive with the minimum number.
But we're not inclusive with the maximum number.
Then we can go ahead and check to see if this distance is within this particular range.
So if number in range will pass our distance here.
And the minimum value is going to be our range dot min.
And the max is going to be range dot max.
If it's within that range then we can go ahead and return the damage we should apply, which is going
to be our properties dot base damage.
And we want to multiply this by the multiplier inside of this range.
So range dot multiplier.
Otherwise.
Let's just say for some reason, somehow we didn't find a range in here.
Then I'm just going to return the properties of base damage.
But this hit event shouldn't fire or detect any parts that are outside of the blast radius for our explosion,
so we shouldn't have to worry about damaging any zombies that are too far away.
But now that we have our get damage function, we can go ahead and get the damage.
So get damage and we'll pass the distance.
And then we can refer to that humanoid and use the take damage function and apply that damage on that
zombie.
And another thing we should account for is if there is a who last damaged value in there.
So that way we can credit that kill or death of the zombie to this player.
So if the hip part dot parent find first child who last damaged, then we can go ahead and set hip part
dot parent dot who last damaged dot value equal to this player.
Now that we are successfully listening to this hit event, we can go ahead and set the position of our
explosion to be equal to the grenade clone dot position.
So wherever our grenade clone is at, we're going to set the explosion to that position, and then we
can go ahead and set the parent of this explosion equal to the workspace.
Or actually we'll make it a child of our grenade clone.
And before we actually want to blow it up, we're also going to anchor our grenade clone.
So that way it doesn't go flying away.
So we're going to anchor it in place.
And then the explosion is going to happen.
And once the explosion happens we're going to set the grenade clones transparency equal to one.
And then we want to go ahead and emit particles out of our grenade clone.
So grenade clone dot explosion emitter we're going to emit from the properties dot explosion particle
amount.
And then inside of the grenade clone we're going to get the smoke emitter.
And we're going to emit the properties dot smoke particle amount.
And then we also want to go ahead and play the explosion sound.
So grenade clone dot explosion sound.
We're going to play that.
And finally we can go ahead and use the debris service and add an item which is going to be our grenade
clone.
And we're going to destroy after the lifetime after explosion.
Cool.
The next thing we want to go ahead and do is we want to be able to notify or tell the player how many
grenades they have left inside of the grenade, because they're not going to be able to see these attributes.
So what we should do is we should update the name of the tool, and it should tell them how many grenades
they have left.
So because we are manipulating the attributes of our tool here, we should listen for when those attributes
change.
So we're going to listen to the attribute change event, connect a function and get the name of the
attribute that changed.
And if the name of that attribute is equal to the grenades left attribute, then we can go ahead and
set the name of the tool equal to grenade, and then we can put inside of parentheses how many grenades
are left.
So we will make sure to concatenate this with the tool get attribute.
And that's going to be grenades left.
And concatenate that.
Otherwise.
What we can do is we can check if the tool get attribute grenades left is equal to zero, and if it
is, then that means we should make the handle of the grenade or this model.
We should make it invisible.
So that way it looks like we don't have any grenades left.
So tool dot handle dot transparency set it equal to one.
Otherwise we can go ahead and set tool dot handle dot transparency back to be opaque.
And then the last thing we can do is just copy this code right here and paste it inside of the main
section.
So that way when we're initializing this tool, it's going to update the name of the grenade to reflect
how many grenades are left.
Okay.
So let's go ahead and test what we've gotten written down so far.
I'm going to move this grenade into my starter pack.
And then we'll go and play test.
And unfortunately, we we got an error.
Oh, that's because it's from our shop handler.
Because it's trying to find the grenade in server storage, but it's not inside of there.
So I'm just going to ignore that error for now.
But we can go ahead and play our game.
And let me see if I can go ahead and throw it.
So I click there you go.
There's our grenade and it should blow up.
Boom.
As you can see, the grenade in our hand is now invisible because we don't have any grenades left.
So now what we should do is we should implement the ability for us to open up the shop and buy more
grenades and add extra grenades into our grenade tool.
So inside of the shop handler, when the player wants to purchase a tool and we clone it and give it
to him, we specifically want to check if this tool is going to be a grenade.
So if the name of the item the player is trying to buy is equal to grenade, then we don't want to create
or give them a new tool.
Instead, we want to check if the player already has a grenade tool on them, and if they do, we want
to go ahead and change the attribute of grenades left on that tool so we can go ahead and see if we
can find a grenade tool on them.
We'll call this grenade tool and we'll set it equal to nil for now because we're going to.
Check and loop through every single tool that is inside of the player's backpack.
So in player backpack, get children.
And that's because the name of the tool is not going to be exactly grenade.
Because if you remember inside of our server script, we're updating the name of the tool to reflect
how many grenades are left.
So we need to loop through all the tools in the player's backpack and check to see if the name of this
tool includes the word of grenade.
So if string dot find.
Inside of this tool's name.
The word of grenade.
Then that means they're grenade tools inside of their backpack, and we can go ahead and set the grenade
tool variable equal to the tool we found.
And then we'll just break out of this loop.
Otherwise.
Let's say we didn't find the grenade tool in their backpack.
Well, that could mean that they are holding it instead.
So if we did not find a grenade tool yet, then what we can go ahead and do is we'll set grenade tool
equal to player dot character, find first child, which is a tool.
So whatever tool the player is holding will set to grenade tool.
Now of course the player might not have any grenade tool on them at all.
So what we need to do instead is we need to check if we have a grenade tool.
And this particular tool has the attribute of grenades left.
So that way we know for sure that yep this is a grenade.
So if there's a grenade tool and we have on this grenade tool the attribute of grenades left.
Then we can go ahead and update the property on this grenade tool.
However, we only want to do that if the grenades left inside of our grenade is not already equal to
the max grenades that we can hold.
So if grenade tool get attribute grenades left, if that's equal to the grenade tool, get attribute
of max grenades, then we're just going to return because the player can't buy any more grenades.
They already have the maximum amount allowed.
Otherwise we can go ahead and set on this attribute of grenades left to be equal to grenade tool.
Get attribute grenades left plus one.
And then we can go ahead and make sure to deduct the amount of money from the player's leader stats.
So player dot leader stats dot money dot value is equal to the after balance.
And then we're just going to return because we don't want to clone a new grenade tool and give it to
them.
However.
If we did not find a grenade tool in this player's inventory or on their character, then we'll go ahead
and clone the grenade tool and place it in the player's backpack.
So now what we can go ahead and do is I'm going to move my grenade tool back inside of server storage
and in my tools folder.
And we're going to go and play test the game.
Or hop into the game, and then I want to give my players some money.
So we'll go to the server and we'll update the money to a whole bunch of money, and then we'll go back
to the client.
Let's go ahead and head to the shop.
We'll open this up and let's see if we can buy a grenade.
So if I click this boom we got one grenade.
If I click it again as you can see now it's updating the attribute for my grenade.
And I can keep buying it.
And then once I've gotten ten grenades, as you can see I can't buy any more.
So now let's go ahead and see if our grenades can hurt some zombies.
So we'll run over here to where the zombies spawn.
Let's go ahead and throw it.
We'll throw a few.
And just like that, boom!
It killed all of our zombies.
Let's go ahead and run over here.
And let's throw a grenade down.
I might have thrown that a little bit.
Yeah, a little bit early.
But you can see that the range of the grenade actually works just fine.
So instead of instantly killing that zombie, it only dealt half of its health.
Pretty cool.
But let me throw another grenade, get them to run over it.
There we go.
Now they're dead.
And then we got one last guy coming after us.
Actually, let me just knife him up here, and then we can go and throw another grenade.
And if you can tell, as you can see, the server's calculating the direction where I should be throwing
the grenade.
And it's applying that direction to the grenade.
So it looks like I'm throwing it.
Very cool.
Okay, and our game should be complete.
Congratulations.
The only thing left for us to do is to go and playtest our game, make sure everything is working,
and then we can go ahead and publish the game.
I'll see you in the next lecture.